package com.ltu.m7011e.imagine.sudoku.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.ltu.m7011e.imagine.sudoku.client.Game;

public class Sudoku extends Game implements EntryPoint
{
	private AsyncCallback<String> callback;
	private SudokuServiceAsync reverserService;
	
	private VerticalPanel container = new VerticalPanel();
	private VerticalPanel panel = new VerticalPanel();
	private HorizontalPanel[] rows = new HorizontalPanel[9];
	
	private static final int BOX_SIZE = 3;
	private static final int BOARD_SIZE = BOX_SIZE*BOX_SIZE;
	private final int[][] cells = new int[BOARD_SIZE][BOARD_SIZE];
	
	public Sudoku()
	{
		DOM.setElementAttribute(container.getElement(), "id", "game");
		
		container.add(panel);
		
		gameContainer.add(timeLabel);
		gameContainer.add(container);
		gameContainer.setWidth("100%");
		gameContainer.setCellHorizontalAlignment(panel, HasHorizontalAlignment.ALIGN_CENTER);
		
		setUpRPC();
		reverserService.getCells("cells", callback);
	}
	
	private void result(String data)
	{
		String[] split = data.split(",");
		
		if(split[0].compareTo("grid") == 0)
		{
			drawGrid(split[1]);
		}
		else if(split[0].compareTo("correct") == 0)
		{
			Window.alert(split[1]);
		}
		else
		{
			Window.alert(data);
		}
	}
	
	/**
	 * Draws the grid and ads a KeyHandler.
	 */
	private void drawGrid(String data)
	{
		char[] input = data.toCharArray();
		panel.addStyleName("suduku");
		
		SudokuHandler handler = new SudokuHandler();
		
		int k = 0;
		for(int i = 0; i < BOARD_SIZE; i++)
		{
			rows[i] = new HorizontalPanel();
			rows[i].addStyleName("sudoku-row");
			
			for(int j = 0; j < BOARD_SIZE; j++)
			{
				TextBox cell = new TextBox();
				if(input[k] != '0')
				{
					cell.setValue("" + input[k]);
					cell.addStyleName("sudoku-cell-ro");
					cell.setReadOnly(true);
				}
				cell.addKeyPressHandler(handler);
				cell.addStyleName("sudoku-cell");
				cell.setName("c_" + i + "_" + j);
				cell.getElement().setId("c_" + i + "_" + j);

				rows[i].add(cell);
				cells[i][j] = input[k]-48;
				k++;
			}
			
			panel.add(rows[i]);
		}
	}
	
	public void onModuleLoad()
	{
	}
	
	/**
	 * Get a textbox from the grid.
	 * @param row
	 * @param column
	 * @return
	 */
	private TextBox getWidget(int row, int column)
	{
		return (TextBox) ((HorizontalPanel) panel.getWidget(row)).getWidget(column);
	}
	
	/**
	 * KeyHandler
	 */
	class SudokuHandler implements KeyPressHandler
	{
		public void onKeyPress(KeyPressEvent event)
		{
			int keyCode = event.getCharCode();
			
			TextBox element = (TextBox) event.getSource();
			String name = element.getName();
			String[] split = name.split("_");
			int row = Integer.parseInt(split[1]);
			int column = Integer.parseInt(split[2]);
			
			if(keyCode == KeyCodes.KEY_UP && 0 < row)
			{
				move(row-1, column);
			}
			else if(keyCode == KeyCodes.KEY_DOWN && row < 8)
			{
				move(row+1, column);
			}
			else if(keyCode == KeyCodes.KEY_LEFT && 0 < column)
			{
				move(row, column-1);
			}
			else if(keyCode == KeyCodes.KEY_RIGHT && column < 8)
			{
				move(row, column+1);
			}
			else if(48 <= keyCode && keyCode <= 57)
			{
				int num = keyCode - 48;
				if(0 < num)
				{
					element.setValue("" + num);
				}
				event.preventDefault();
				
				String[] id = DOM.getElementAttribute(element.getElement(), "id").split("_");
				int rowIndex = Integer.parseInt(id[1]);
				int colIndex = Integer.parseInt(id[2]);
				cells[rowIndex][colIndex] = num;
				
				reverserService.getCells("correct,"+gridToString(), callback);
			}
			else if(57 < keyCode)
			{
				// TODO - backspace and delete key must work.
				
				// Block all attempts to enter text.
				event.preventDefault();
			}
		}
		
		/**
		 * Help method to move around the cells.
		 * @param row
		 * @param column
		 */
		private void move(int row, int column)
		{
			getWidget(row, column).setFocus(true);
		}
	}
	
	private void setUpRPC()
	{
		reverserService = (SudokuServiceAsync) GWT.create(SudokuService.class);
		((ServiceDefTarget) reverserService).setServiceEntryPoint(GWT.getModuleBaseURL() + "Games/SudokuService");
		callback = new AsyncCallback<String>()
		{
			// This method will be called if the service call fails   
			public void onFailure(Throwable caught)
			{
				// Show a message informing the user why the call failed   
				Window.alert("Failed to get response from server" + caught.getMessage());
			}
			
			// This method will be called if the service call succeeds   
			public void onSuccess(String data)
			{
				// Get the service call result and cast it to the desired type and display it
				result(data);
			}
		};
	}
	
	private String gridToString()
	{
		String grid = "";
		for(int i = 0; i < BOARD_SIZE; i++)
		{
			for(int j = 0; j < BOARD_SIZE; j++)
			{
				grid += cells[i][j];
			}
		}
		
		return grid;
	}
}
